<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * 命令模式的主要用途是把调用对象（用户界面、API和代理等）与实现操作的对象隔离开。凡是两个对象之间互动的方式需要有更高的模块化程度时，
    * 都可以使用这种模式。
    *
    * 发送者（发出命令、调用命令对象）--> 命令对象（接收命令、调用接收者的命令接口）--> 接收者
    *
    * */
    //将军下达进攻命令 --> 鼓手击鼓（接收进攻命令、调用士兵的进攻接口）--> 士兵听到鼓声发起冲锋

    //士兵（接收者）
    class Soldier{
        exec(){
            console.log("士兵:听到鼓声，士兵开始冲锋!")
        }
    }

    //击鼓手（命令对象）
    class Drummer{
        constructor(obj){ //命令对象中接收一个接收者对象
            this.soldier = obj
        }
        drum(){
            console.log("击鼓手:击鼓手击鼓中，咚咚咚!") //击鼓手击鼓发出进攻信号
            this.soldier.exec() //命令对象（击鼓手）传达发送者（将军）的进攻信号给接收者（士兵），调用士兵的进攻方法
        }
    }

    //将军（发送者）
    class Invoker{
        constructor(obj){ //发送者中接收一个命令对象
            this.drummer = obj
        }
        command(){
            console.log("将军:准备进攻，击鼓手给我击鼓!") //下达进攻命令
            this.drummer.drum() //命令击鼓手击鼓（调用击鼓手的击鼓方法）
        }
    }

    //实例化对象
    let soldier = new Soldier() //接收者（士兵对象）
    let drummer = new Drummer(soldier) //击鼓手对象（调用接收者士兵的接口，所以把士兵对象传进来）
    let invoker = new Invoker(drummer) //发送者（将军对象）执行，接收命令对象（击鼓手）

    //最后只需要将军下达命令即可
    invoker.command()


    //es5的写法

    //接收者
    var skills = {
        Q:function (){
            console.log("斩无极")
        },
        W:function (){
            console.log("快雪时晴")
        },
        E:function (){
            console.log("千山吹雪")
        },
        R:function (){
            console.log("逍遥游")
        }
    }

    //命令对象
    var command = function (key){ //接收从发送者传来的键码
        return function (){ //返回一个函数对象
            skills[key]() //接收者对象根据传入的key来执行相对应的命令
        }
    }

    //发送者
    document.onkeypress = function (e){
        var keyCode = e.keyCode
        var commands = { //映射表
            "113":"Q",
            "119":"W",
            "101":"E",
            "114":"Q",
        }

        var c = command(commands[keyCode]) //将命令对象执行后返回的函数赋给变量c
        c() //执行返回的函数
    }

</script>
</body>
</html>